﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.Mvc;
using System.IO;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;

namespace MvcStudy.Models
{
    public class HtmlFilterNet : ActionFilterAttribute
    {
        #region = IsAvailable =  
  
        private bool _isavailable = true;  
  
        public bool IsAvailable  
        {  
            get { return _isavailable; }  
            set { _isavailable = value; }  
        }  
 
        #endregion  
        private TextWriter _originalWriter;  
        private static readonly MethodInfo SwitchWriterMethod = typeof(HttpResponse).GetMethod("SwitchWriter", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);  
        public HtmlFilterNet() { }
        public HtmlFilterNet(bool isAvailable)  
        {  
            _isavailable = isAvailable;  
        }  
        public string SetGray(string text)  
        {  
            text = HtmlHelper.Compress(text);  
            if (DateTime.Now.Month == 4 && DateTime.Now.Day == 21)  
            {  
                text = Regex.Replace(text, "</head>", @"<style type=""text/css"">html {filter:gray;}</style></head>  
", RegexOptions.IgnoreCase);  
            }  
            return text;  
        }  
        public override void OnActionExecuting(ActionExecutingContext filterContext)  
        {
            if (!IsAvailable)
#if DEBUG
                return; 
#endif  
            _originalWriter = (TextWriter)SwitchWriterMethod.Invoke(HttpContext.Current.Response, new object[] { new HtmlTextWriter(new StringWriter()) });  
            base.OnActionExecuting(filterContext);  
        }  
        public override void OnResultExecuted(ResultExecutedContext filterContext)  
        {  
            base.OnResultExecuted(filterContext);  
            if (!IsAvailable)  
#if DEBUG  
            return;  
#endif  
  
            HtmlTextWriter cacheWriter = (HtmlTextWriter)SwitchWriterMethod.Invoke(HttpContext.Current.Response, new object[] { _originalWriter });  
            string textWritten = cacheWriter.InnerWriter.ToString();  
            if (filterContext.HttpContext.Response.ContentType == "text/html")  
            {  
                textWritten = Compress(textWritten).ToString();  
            }  
            filterContext.HttpContext.Response.Write(textWritten);  
            //filterContext.RequestContext.HttpContext.Response.Filter = new HtmlStreamFilter(filterContext.RequestContext.HttpContext.Response.Filter, filterContext.RequestContext.HttpContext.Response.ContentEncoding, SetGray);  
        }  
        private static StringBuilder Compress(string text)  
        {  
            StringBuilder str = new StringBuilder();  
            StringBuilder strlink = new StringBuilder();  
            var s = new char[] { '\f', '\n', '\r', '\t', '\v' };  
            Func<int, object> P = c => null;  
            Func<int, object> Ptag = c => null; //标签处理机  
            Func<int, object> Pcomment = c => null; //注释  
 
            #region - 总处理机 -  
            Func<int, object> state = P = i =>  
            {  
                char c = text[i];  
                if (c == '<') //碰到<交个Ptag处理机  
                {  
                    if (i + 4 < text.Length)  
                    {  
                        if (text.Substring(i + 1, 3) == "!--") //交个注释处理机  
                        {  
                            return Pcomment;  
                        }  
                    }  
                    str.Append(c);  
                    return Ptag;  
                }  
                else if (s.Contains(c) == true) { return P; }  
                else if (c == ' ')  
                {  
                    if (i + 1 < text.Length)  
                    {  
                        if (s.Union(new char[] { ' ', '<' }).Contains(text[i + 1]) == false)  
                        {  
                            str.Append(c);  
                        }  
                    }  
                    return P;  
                }  
                else  
                {  
                    str.Append(c);  
                    return P;  
                }  
            };  
            #endregion  
 
            #region - Tag处理机 -  
            Ptag = i =>  
            {  
                char c = text[i];  
                if (c == '>') //交还给p  
                {  
                    str.Append(c);  
                    return P;  
                }  
                else if (s.Contains(c) == true) { return Ptag; }  
                else if (c == ' ')  
                {  
                    if (i + 1 < text.Length)  
                    {  
                        if (new char[] { ' ', '/', '=', '>' }.Contains(text[i + 1]) == false)  
                        {  
                            str.Append(c);  
                        }  
                    }  
                    return Ptag;  
                }  
                else  
                {  
                    str.Append(c);  
                    return Ptag;  
                }  
            };  
            #endregion  
 
            #region - 注释处理机 -  
            Pcomment = i =>  
            {  
                char c = text[i];  
                if (c == '>' && text.Substring(i - 2, 3) == "-->")  
                {  
                    return P;  
                }  
                else  
                {  
                    return Pcomment;  
                }  
            };  
            #endregion  
  
            for (int index = 0; index < text.Length; index++)  
            {  
                state = (Func<int, object>)state(index);  
            }  
  
            return str;  
        }  
    }
}